#include "../inc/user.h"
#include <fstream>
#include <sstream>
#include <algorithm>

// User 类实现
User::User() = default;

User::User(const std::string &uname, const std::string &pwd)
    : username(uname), password(pwd)
{
    gameScores["Snake"] = 0;
    gameScores["2048"] = 0;
}

std::string User::getUsername() const { return username; }
std::string User::getPassword() const { return password; }
const std::unordered_map<std::string, int> &User::getGameScores() const { return gameScores; }

bool User::verifyPassword(const std::string &pwd) const
{
    return password == pwd;
}

bool User::changePassword(const std::string &oldPwd, const std::string &newPwd)
{
    if (password == oldPwd)
    {
        password = newPwd;
        return true;
    }
    return false;
}

void User::displayAllScores() const
{
    std::cout << "Game scores for user " << username << ":\n";
    for (const auto &pair : gameScores)
    {
        std::cout << "  " << pair.first << ": " << pair.second << "\n";
    }
}

std::string User::serialize() const
{
    std::ostringstream oss;
    oss << username << "\n";
    oss << password << "\n";
    oss << gameScores.size() << "\n";
    for (const auto& pair : gameScores) {
        oss << pair.first << "\n" << pair.second << "\n";
    }
    return oss.str();
}

User User::deserialize(const std::vector<std::string>& lines, size_t& index)
{
    User user;
    user.username = lines[index++];
    user.password = lines[index++];
    
    int scoreCount = std::stoi(lines[index++]);
    for (int i = 0; i < scoreCount; ++i) {
        std::string gameName = lines[index++];
        int score = std::stoi(lines[index++]);
        user.gameScores[gameName] = score;
    }
    
    return user;
}

// UserManager 类实现
UserManager::UserManager()
{
    loadUsers();//加载用户数据
}

UserManager::~UserManager()
{
    saveUsers();//保存用户数据
}

    /**
     * @brief 创建新用户
     *
     * 创建一个新用户，并将其添加到用户列表中。
     * 如果用户名已存在，则创建失败，返回false。
     * 如果用户名不存在，则创建成功，将新用户添加到用户列表中，并调用saveUsers()方法保存用户数据，返回true。
     *
     * @param username 用户名
     * @param password 密码
     * @return 如果创建成功返回true，如果用户名已存在返回false
     */
bool UserManager::createUser(const std::string &username, const std::string &password)
{
    for (const auto &user : users)
    {
        if (user.getUsername() == username)
        {
            return false;
        }
    }
    users.emplace_back(username, password);//添加用户
    saveUsers();//保存用户数据
    return true;
}

/**
 * @brief 对用户进行身份验证
 *
 * 遍历用户列表，通过用户名和密码对用户进行身份验证。
 *
 * @param username 用户名
 * @param password 密码
 * @return 指向成功验证用户的指针，如果验证失败则返回nullptr
 */
User *UserManager::authenticate(const std::string &username, const std::string &password)
{
    for (auto &user : users)
    {
        if (user.getUsername() == username && user.verifyPassword(password))
        {
            return &user;
        }
    }
    return nullptr;
}

/**
 * @brief 获取所有用户列表
 *
 * 返回当前 UserManager 对象中保存的所有用户列表的引用。
 *
 * @return 返回用户列表的常量引用
 */
const std::vector<User> &UserManager::getAllUsers() const
{
    return users;
}

/**
 * @brief 显示游戏排行榜
 *
 * 显示指定游戏中得分最高的前N名玩家的排行榜。
 *
 * @param gameName 游戏名称
 * @param topN 需要显示的前N名玩家
 */
void UserManager::displayLeaderboard(const std::string& gameName, int topN)
{
    std::vector<std::pair<std::string, int>> scores;
    //创建ShowFont对象
    ShowFont* usershowFont = ShowFont::instance();
    char user_second_text[200];
    char user_first_text[200];

    for (const auto& user : users) 
    {
        int score = user.getGameScores().count(gameName) ? user.getGameScores().at(gameName) : -1;
        if (score > 0)
        {  
            scores.emplace_back(user.getUsername(), score);
        }
    }
    
    //
    std::sort(scores.begin(), scores.end(), 
        [](const std::pair<std::string, int>& a, const std::pair<std::string, int>& b) 
        {
            return a.second > b.second;
        });
    
    //显示标题
    std::cout << "\n=== " << gameName << " Leaderboard ===\n";
    std::cout << "Rank\tPlayer\t\tScore\n";
    std::cout << "--------------------------------\n";
    
    //显示排行榜数据
    int displayCount = std::min(topN, static_cast<int>(scores.size()));
    int XPos = 175;
    for (int i = 0; i < displayCount; ++i) 
    {
        std::cout << (i + 1) << ".\t" << scores[i].first << "\t\t" << scores[i].second << "\n";

        sprintf(user_first_text,"%s",scores[i].first.c_str());
        sprintf(user_second_text,"%d",scores[i].second);
        usershowFont->display(user_first_text, 32, 100, 32, ShowFont::black, ShowFont::white, 270, XPos);
        usershowFont->display(user_second_text, 32, 100, 32, ShowFont::black, ShowFont::white, 480, XPos);
        XPos += 40;
    }
    
    if (scores.empty()) 
    {
        std::cout << "No records found for this game.\n";
    }
}

/**
 * @brief 更新用户游戏分数
 *
 * 根据用户名和游戏名称更新用户对应的游戏分数。如果新分数高于当前分数则更新，
 * 否则保持不变。如果游戏名称不存在，则新增该游戏的分数记录。
 *
 * @param username 用户名
 * @param gameName 游戏名称
 * @param score 新的游戏分数
 */
void UserManager::updateUserScore(const std::string &username, const std::string &gameName, int score)
{
    for (auto &user : users)
    {
        if (user.getUsername() == username)
        {
            auto& gameScores = const_cast<std::unordered_map<std::string, int>&>(user.getGameScores());
            if (gameScores.find(gameName) != gameScores.end())
            {
                if (score > gameScores[gameName])
                {
                    gameScores[gameName] = score;
                }
            }
            else
            {
                gameScores[gameName] = score;
            }
            saveUsers();
            return;
        }
    }
}


/**
 * @brief 获取用户的最高得分
 *
 * 在用户列表中查找指定用户名对应的用户，并在该用户的游戏得分中查找指定游戏的最高得分。
 *
 * @param username 用户名
 * @param gameName 游戏名称
 * @return 如果找到指定用户名和游戏名称对应的最高得分，则返回该得分；
 *         如果未找到指定用户名，或未找到指定游戏名称的得分，则返回 -1。
 */
int UserManager::getUserHighScore(const std::string &username, const std::string &gameName) const
{
    for (const auto &user : users)
    {
        if (user.getUsername() == username)//找到用户
        {
            auto it = user.getGameScores().find(gameName);//查找游戏得分
            if (it != user.getGameScores().end())//找到游戏得分
            {
                return it->second;//返回最高得分
            }
            return -1;
        }
    }
    return -1;
}

/**
 * @brief 保存用户信息到文件中
 *
 * 将用户信息保存到指定的文件中。如果文件无法打开，会输出错误信息并返回。
 *
 * @param filename 文件名
 */
void UserManager::saveUsers()
{
    std::ofstream outFile(filename);
    if (!outFile)
    {
        std::cerr << "Error: Could not open file for writing: " << filename << std::endl;
        return;
    }

    outFile << users.size() << "\n";
    for (const auto& user : users) {
        outFile << user.serialize();
    }
}

/**
 * @brief 从文件中加载用户信息
 *
 * 从指定的文件中读取用户信息，并将其加载到用户管理器中。
 *
 * @note 如果文件无法打开或文件为空，则不进行任何操作。
 */
void UserManager::loadUsers()
{
    std::ifstream inFile(filename);
    if (!inFile)
    {
        return;
    }

    std::vector<std::string> lines;
    std::string line;
    while (std::getline(inFile, line)) {
        lines.push_back(line);
    }

    if (lines.empty()) return;

    size_t index = 0;
    int userCount = std::stoi(lines[index++]);
    users.clear();

    for (int i = 0; i < userCount && index < lines.size(); ++i) {
        users.push_back(User::deserialize(lines, index));
    }
}
